if g:has_terminal == 0
    finish
endif
if v:version >= 801 && !has('nvim') && Require('termdebug')
    let g:debug_tool = 'termdebug'
    let g:termdebug_map_K = 1
    let g:termdebug_use_prompt = 1
    packadd termdebug
    " breakpoint
    nnoremap <M-d><Cr>  :Break<Space>
    nnoremap <M-d><Space> :Clear<Space>
    nnoremap <M-d><M-d> :Continue<Cr>
    nnoremap <M-d>n :Over<Cr>
    nnoremap <M-d>i :Step<Cr>
    nnoremap <M-d>o :Finish<Cr>
    nnoremap <F3>  :Stop<Cr>
    nnoremap <F4>  :Until<Cr>
    nnoremap <F5>  :Continue<Cr>
    nnoremap <F6>  :Over<Cr>
    nnoremap <F7>  :Step<Cr>
    nnoremap <F8>  :Finish<Cr>
    nnoremap <F9>  :Break<Space>
    nnoremap <F10> :Clear<Space>
    " command
    nnoremap <M-d>t :Termdebug<Space>
    nnoremap <M-d>T :TermdebugCommand<Space>
    nnoremap <M-d>a :Arguments<Space>
    nnoremap <M-d>r :Run<Space>
    " debug
    nnoremap <silent>J :Evaluate<Space>
    nnoremap <M-d>w :Winbar<Cr>
    " other
    nnoremap <M-d>P :Program<Cr>
    nnoremap <M-d>A :Asm<Cr>
    nnoremap <M-d>s :Source<Cr>
    nnoremap <M-d>g :Gdb<Cr>
elseif Installed('nvim-dap', 'nvim-dap-ui')
    let g:debug_tool = 'nvim-dap'
    if get(g:, 'leovim_loaded', 0) == 0
        luafile $LUA_PATH/dap.lua
    endif
    if filereadable(expand("~/.leovim.d/adapter.lua"))
        luafile ~/.leovim.d/adapter.lua
        nnoremap <M-d>L :luafile ~/.leovim.d/adapter.lua<Cr>
    endif
    " load template
    function! ReadNvimdapTemplate(template) abort
        execute '0r ' . $LEOVIM_PATH . '/nvim-dap/' . a:template
    endfunction
    function! s:open_nvim_dap()
        if InstalledFzf()
            tabe ~/.leovim.d/adapter.lua
            if WINDOWS()
                call fzf#run({
                            \ 'window': {'width': 0.6, 'height': 0.6, 'border': 'sharp'},
                            \ 'source': 'dir /b /a-d ' . $LEOVIM_PATH . '\\nvim-dap',
                            \ 'sink': function('ReadNvimdapTemplate')
                            \ })
            else
                call fzf#run({
                            \ 'window': {'width': 0.6, 'height': 0.6, 'border': 'sharp'},
                            \ 'source': 'ls -1 ' . $LEOVIM_PATH . '/nvim-dap',
                            \ 'sink': function('ReadNvimdapTemplate')
                            \ })
            endif
        endif
    endfunction
    command! OpenDapAdaptor call s:open_nvim_dap()
    nnoremap <M-d>O :OpenDapAdaptor<Cr>
    " core keymaps
    nnoremap <silent><M-d><Cr> <cmd>lua require("dap").toggle_breakpoint()<Cr>
    nnoremap <silent><M-d><M-d> <cmd>lua require("dap").continue()<Cr>
    nnoremap <silent><M-d>n <cmd>lua require("dap").step_over()<Cr>
    nnoremap <silent><M-d>i <cmd>lua require("dap").step_into()<Cr>
    nnoremap <silent><M-d>o <cmd>lua require("dap").step_out()<Cr>
    nnoremap <silent><F3>  <cmd>lua require("dap").disconnect({ terminateDebuggee = true });require"dap".close()<Cr>
    nnoremap <silent><F4>  <cmd>lua require("dap").run_to_cursor()<Cr>
    nnoremap <silent><F5>  <cmd>lua require("dap").continue()<Cr>
    nnoremap <silent><F6>  <cmd>lua require("dap").step_over()<Cr>
    nnoremap <silent><F7>  <cmd>lua require("dap").step_into()<Cr>
    nnoremap <silent><F8>  <cmd>lua require("dap").step_out()<Cr>
    nnoremap <silent><F9>  <cmd>lua require("dap").toggle_breakpoint()<Cr>
    nnoremap <silent><F10> <cmd>lua require("dap").set_breakpoint(vim.fn.input('Breakpoint condition: '))<Cr>
    " view, NOTE: preview is like eval in vimspector
    nnoremap <silent>- <cmd>lua require("dap.ui.widgets").hover()<Cr>
    nnoremap <silent>= <cmd>lua require("dap.ui.widgets").preview()<Cr>
    nnoremap <silent><M-d>f <cmd>lua require("dap.ui.widgets").centered_float(widgets.scopes)<Cr>
    " basic <M-d> map
    nnoremap <M-d>l :lua require("dap").
    nnoremap <silent><M-d>q <cmd>lua require("dap").close()<Cr>
    nnoremap <silent><M-d>p <cmd>lua require("dap").pause()<Cr>
    nnoremap <silent><M-d>R <cmd>lua require("dap").run_last()<Cr>
    nnoremap <silent><M-d>a <cmd>lua require("dap").attach(vim.fn.input('Attatch to: '))<Cr>
    nnoremap <silent><M-d>N <cmd>lua require("dap").step_back()<Cr>
    " breakpoints
    nnoremap <silent><M-d>b <cmd>lua require("dap").list_breakpoints()<Cr>
    nnoremap <silent><M-d>c <cmd>lua require("dap").clear_breakpoints()<Cr>
    nnoremap <silent><M-d>E <cmd>lua require("dap").set_exception_breakpoints("")<left><left>
    " debug
    nnoremap <silent><M-d>u <cmd>lua require("dap").up()<Cr>
    nnoremap <silent><M-d>d <cmd>lua require("dap").down()<Cr>
    nnoremap <silent><M-d>g <cmd>lua require("dap").launch(vim.fn.input('Get config: '))<Cr>
    " repl
    nnoremap <silent><M-d>t <cmd>lua require("dap").repl.toggle()<Cr>
    nnoremap <silent><M-d>s <cmd>lua require("dap").repl.open({}, 'split')<Cr>
    nnoremap <silent><M-d>v <cmd>lua require("dap").repl.open({}, 'vsplit')<Cr>
    " auto attach
    au FileType dap-repl lua require('dap.ext.autocompl').attach()
    " --------------------------------------
    " nvim-dap-ui
    " ---------------------------------------
    nnoremap <M-m>l :lua require("dapui").
    nnoremap <silent>J <cmd>lua require("dapui").eval()<Cr>
    nnoremap <silent><M-m><M-m> <cmd>lua require("dapui").toggle()<Cr>
    " watch
    nnoremap <silent><M-m>f <cmd>lua require("dapui").float_element()<Cr>
    nnoremap <silent><M-m>r <cmd>lua require("dapui").float_element('repl')<Cr>
    nnoremap <silent><M-m>b <cmd>lua require("dapui").float_element('breakpoints')<Cr>
    nnoremap <silent><M-m>s <cmd>lua require("dapui").float_element('stacks')<Cr>
    nnoremap <silent><M-m>c <cmd>lua require("dapui").float_element('console')<Cr>
    nnoremap <silent><M-m>w <cmd>lua require("dapui").float_element('watches')<Cr>
    " jump to windows in dapui
    nnoremap <silent><M-m>1 :call GoToDAPWindows("DAP Scopes")<Cr>
    nnoremap <silent><M-m>2 :call GoToDAPWindows("DAP Watches")<Cr>
    nnoremap <silent><M-m>3 :call GoToDAPWindows("DAP Stacks")<Cr>
    nnoremap <silent><M-m>4 :call GoToDAPWindows("[dap-repl]")<Cr>
    nnoremap <silent><M-m>0 :call GoToDAPWindows("DAP Breakpoints")<Cr>
    function! GoToDAPWindows(name) abort
        let windowNr = 0
        try
            let windowNr = bufwinnr(a:name)
        catch
            let windowNr = 0
        endtry
        if windowNr > 0
            execute windowNr . 'wincmd w'
        endif
    endfunction
elseif Installed('vimspector')
    let g:debug_tool = "vimspector"
    if WINDOWS()
        let g:vimspector_base_dir = $DEP_PATH . "\\vimspector"
    else
        let g:vimspector_base_dir = $DEP_PATH . "/vimspector"
    endif
    nmap <silent><F7> <Plug>VimspectorToggleConditionalBreakpoint
    " load template
    function! ReadVimspectorTemplate(template) abort
        execute '0r ' . $LEOVIM_PATH . '/vimspector/' . a:template
    endfunction
    function! s:open_vimspector()
        let path = GitRootPath()
        if empty(path)
            let path = '.'
        endif
        execute printf('tabe %s/.vimspector.json', path)
        if InstalledFzf()
            if WINDOWS()
                call fzf#run({
                            \ 'window': {'width': 0.6, 'height': 0.6, 'border': 'sharp'},
                            \ 'source': 'dir /b /a-d ' . $LEOVIM_PATH . '\\vimspector',
                            \ 'sink': function('ReadVimspectorTemplate')
                            \ })
            else
                call fzf#run({
                            \ 'window': {'width': 0.6, 'height': 0.6, 'border': 'sharp'},
                            \ 'source': 'ls -1 ' . $LEOVIM_PATH . '/vimspector',
                            \ 'sink': function('ReadVimspectorTemplate')
                            \ })
            endif
        endif
    endfunction
    command! OpenVimspector call s:open_vimspector()
    nnoremap <M-d>O :OpenVimspector<Cr>
    " core keymaps
    nmap <M-d>I :VimspectorInstall<Space>
    nmap <silent><M-d><Cr> <Plug>VimspectorToggleBreakpoint
    nmap <silent><M-d><M-d> <Plug>VimspectorContinue
    nmap <silent><M-d>n <Plug>VimspectorStepOver
    nmap <silent><M-d>i <Plug>VimspectorStepInto
    nmap <silent><M-d>o <Plug>VimspectorStepOut
    nmap <silent><F3>  :call vimspector#Reset()<Cr>
    nmap <silent><F4>  <Plug>VimspectorRunToCursor
    nmap <silent><F5>  <Plug>VimspectorContinue
    nmap <silent><F6>  <Plug>VimspectorStepOver
    nmap <silent><F7>  <Plug>VimspectorStepInto
    nmap <silent><F8>  <Plug>VimspectorStepOut
    nmap <silent><F9>  <Plug>VimspectorToggleBreakpoint
    nmap <silent><F10> <Plug>VimspectorToggleConditionalBreakpoint
    " session
    nnoremap <M-d><M-m>m :VimspectorMkSession<Cr>
    nnoremap <M-d><M-m>l :VimspectorLoadSession<Cr>
    nnoremap <M-d><M-m>n :VimspectorNewSession<Space>
    nnoremap <M-d><M-m>d :VimspectorDestroySession<Space>
    nnoremap <M-d><M-m>r :VimspectorRenameSession<Space>
    nnoremap <M-d><M-m>s :VimspectorSwitchToSession<Space>
    " core shortcuts
    nnoremap <M-d>V :call vimspector#
    nnoremap <M-d>v :Vimspector
    " watch && eval
    nmap <silent>J <Plug>VimspectorBalloonEval
    nnoremap <silent>- :VimspectorWatch <C-r>=expand('<cword>')<Cr>
    xnoremap <silent>- :<C-u>VimspectorWatch <C-r>=GetVisualSelection()<Cr>
    nnoremap <silent>_ :call vimspector#DeleteWatch()<Cr>
    nnoremap <silent>= :VimspectorEval <C-r>=expand('<cword>')<Cr>
    " breakpoint
    nmap <silent><M-d>b <Plug>VimspectorBreakpoints
    nmap <silent><M-d>c :call vimspector#ClearBreakpoints()<Cr>
    nmap <silent><M-d>a :call vimspector#AddFunctionBreakpoint('')<left><left>
    nmap <silent><M-d>t :call vimspector#ToggleAllBreakpointsViewBreakpoint()<Cr>
    nmap <silent><M-d>] <Plug>VimspectorJumpToNextBreakpoint
    nmap <silent><M-d>[ <Plug>VimspectorJumpToPreviousBreakpoint
    " start / stop
    nnoremap <silent><M-d>r :call vimspector#Launch()
    nnoremap <silent><M-d>q :call vimspector#Stop({ 'interactive': v:true })<Cr>
    nnoremap <silent><M-d>R :call vimspector#Restart()<Cr>
    nnoremap <silent><M-d>+ :VimspectorDisassemble<Cr>
    " function
    nnoremap <silent><M-d>u :call vimspector#UpFrame()<Cr>
    nnoremap <silent><M-d>d :call vimspector#DownFrame()<Cr>
    " other commands
    nnoremap <silent><M-d>g :call vimspector#GetConfigurations()<Cr>
    nnoremap <silent><M-d>T :call vimspector#SetCurrentThread()<Cr>
    " jump/show windows in vimspector
    nnoremap <silent><M-m>i :call GoToVimspectorWindow('important')<Cr>
    nnoremap <silent><M-m>e :call GoToVimspectorWindow('stderr')<Cr>
    nnoremap <silent><M-m>s :call GoToVimspectorWindow('server')<Cr>
    nnoremap <silent><M-m>c :call GoToVimspectorWindow('Console')<Cr>
    nnoremap <silent><M-m>v :call GoToVimspectorWindow('Vimspector')<Cr>
    nnoremap <silent><M-m>t :call GoToVimspectorWindow('Telemetry')<Cr>
    nnoremap <silent><M-m>1 :call GoToVimspectorWindow('variables')<Cr>
    nnoremap <silent><M-m>2 :call GoToVimspectorWindow('watches')<Cr>
    nnoremap <silent><M-m>3 :call GoToVimspectorWindow('stacktrace')<Cr>
    nnoremap <silent><M-m>4 :call GoToVimspectorWindow('code')<Cr>
    nnoremap <silent><M-m>5 :call GoToVimspectorWindow('terminal')<Cr>
    function! GoToVimspectorWindow(name) abort
        let windowNr = 0
        let name = a:name
        try
            if name ==# 'variables'
                let windowNr = bufwinnr('vimspector.Variables')
            elseif name ==# 'watches'
                let windowNr = bufwinnr('vimspector.Watches')
            elseif name ==# 'stacktrace'
                let windowNr = bufwinnr('vimspector.StackTrace')
            elseif name ==# 'terminal' || name ==# 'code'
                let windowNr = bufwinnr(winbufnr(g:vimspector_session_windows[name]))
            else
                call vimspector#ShowOutput(name)
            endif
        catch
            " pass
        endtry
        if windowNr > 0
            execute windowNr . 'wincmd w'
        endif
    endfunction
else
    nnoremap J <Nop>
endif
if Installed('jupynium.nvim')
    let g:jupynium_url = get(g:, 'jupynium_url', 'localhost:9999/nbclassic')
    lua require("jupynium").setup({ default_notebook_URL = vim.g.jupynium_url, use_default_keybindings = false })
    au FileType python,r call s:map()
    function! s:execute_and_forword() abort
        JupyniumExecuteSelectedCells
        let endline = search('^# %%', 'nW')
        if endline == 0
            let endline = line("$")
        elseif endline != line("$")
            let endline += 1
        endif
        execute "normal! " . endline . 'G'
    endfunction
    command JupyniumExecuteSelectedCellsForword call s:execute_and_forword()
    function! s:map() abort
        command! JupyniumCommands call FzfCallCommands('JupyniumCommands', 'Jupynium', ['JupyniumKernel'])
        command! JupyniumKernelCommands call FzfCallCommands('JupyniumKernelCommands', 'JupyniumKernel', [])
        nmap <buffer><silent>,<Space> :JupyniumCommands<Cr>
        nmap <buffer><silent>,j :JupyniumKernelCommands<Cr>
        nmap <buffer>,a :JupyniumStartAndAttachToServer<Cr>
        nmap <buffer>,s :JupyniumStartSync<Cr>
        nmap <buffer>,S :JupyniumStopSync<Cr>
        nmap <buffer>,k :JupyniumKernelHover<Cr>
        nmap <buffer>,K :JupyniumKernelSelect<Cr>
        nmap <buffer>,c :JupyniumScrollToCell<Cr>
        nmap <buffer>,u :JupyniumScrollUp<Cr>
        nmap <buffer>,d :JupyniumScrollDown<Cr>
        nmap <buffer>,L :JupyniumClearSelectedCellsOutputs<Cr>
        xmap <buffer>,L :JupyniumClearSelectedCellsOutputs<Cr>
        nmap <buffer>,l :JupyniumExecuteSelectedCells<Cr>
        xmap <buffer>,l :JupyniumExecuteSelectedCells<Cr>
        nmap <buffer>,n :JupyniumExecuteSelectedCellsForword<Cr>
    endfunction
endif
" ---------------------------------------
" using vim-floaterm to do repl
" ---------------------------------------
imap <M-e> # %%
imap <M-d> # STEP
imap <M-m> # In[]<Left>
PlugAddOpt 'vim-floaterm-repl'
" basic send, NOTE: bang! means stay
nnoremap <silent><M-e>r :FloatermReplStart!<Cr>
nnoremap <silent><M-e>n :FloatermReplSend<Cr>
xnoremap <silent><M-e>n :FloatermReplSendVisual<Cr>
nnoremap <silent><M-e>l :FloatermReplSend!<Cr>
xnoremap <silent><M-e>l :FloatermReplSendVisual!<Cr>
nnoremap <silent><M-e>q :FloatermReplSendExit<Cr>
nnoremap <silent><M-e>L :FloatermReplSendClear<Cr>
nnoremap <silent><M-e>k :FloatermReplSendWord<Cr>
xnoremap <silent><M-e>k :FloatermReplSendVisualSelect<Cr>
nnoremap <silent><M-e><Cr> :FloatermReplSendNewlineOrStart<Cr>
xnoremap <silent><M-e><M-e> :FloatermReplSendVisual<Cr>
xnoremap <silent><M-e><Space> :FloatermReplSendVisual!<Cr>
" block send
nnoremap <silent><M-e><M-e> :FloatermReplSendBlock<Cr>
nnoremap <silent><M-e><Space> :FloatermReplSendBlock!<Cr>
" send above, below, all lines
nnoremap <silent><M-e>b :FloatermReplSendFromBegin!<Cr>
nnoremap <silent><M-e>e :FloatermReplSendToEnd!<Cr>
nnoremap <silent><M-e>s :FloatermReplSendAll!<Cr>
